import Link from "next/link"; import { notFound } from "next/navigation"; import { adminPaper, taxonomy } from "@/lib/admin/queries"; import { requireUserPage } from "@/lib/auth/guard"; import { csrfToken } from "@/lib/auth/session"; import { deletePaperAction, redirectAction, relationAction, setStatusAction, updatePaperAction, versionAction } from "@/lib/admin/actions"; import { Csrf, Field, Notice, PageTitle } from "@/components/admin-ui"; import { PaperForm } from "../paper-form"; import { UploadForm } from "./upload-form"; export default async function EditPaper({ params, searchParams }: { params: Promise<{ id: string }>; searchParams: Promise> }) { const { id } = await params; const sp = await searchParams; const u = await requireUserPage(); const [p, tax] = await Promise.all([adminPaper(id), taxonomy()]); if (!p) notFound(); const csrf = csrfToken(u); return (
{p.status === "published" && View public page ↗}
Status {(["draft", "reserved", "published", "withdrawn", "superseded"] as const).filter((st) => st !== p.status).map((st) =>
{(st === "withdrawn" || st === "superseded") && })} {p.status !== "published" &&
}

Publishing requires explicit approval here; nothing is published automatically. Withdrawn papers keep their record and identifier.

Versions

{p.versions.map((v: Record) => )}
#LabelDateDescriptionFileActions
{v.version_no}{v.is_current && current}{v.withdrawn && withdrawn}
{v.file_id ? <>{v.pages ?? "?"} p. · {v.integrity_ok === false ? integrity failed : v.integrity_ok ? "ok" : "pending"} · text {v.text_status}
{String(v.sha256 ?? "").slice(0, 12)} · PDF : "—"}
{!v.is_current &&
} {v.withdrawn ?
:
}

Upload a new version (PDF)

Relations ({p.relations.length})

    {p.relations.map((r: Record) =>
  • {r.kind}{r.inferred ? " · inferred" : ""}{r.identifier} {r.title} — {r.explanation}{r.kind === "curated" &&
    }
  • )}

Add a curated relation (both directions)

Redirects to this paper

    {p.redirects.map((r: Record) =>
  • {r.from_path} → {r.to_path} ({r.status})
  • )}
); }